home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_65 / sounddev.cpp < prev   
C/C++ Source or Header  |  1995-01-01  |  8KB  |  239 lines

  1. // SoundDev.cpp
  2.  
  3. // General sound functions that can be applied to derived sound classes
  4. // (eg SbDevice)
  5.  
  6. // Written by Christopher M. Box (1993)
  7.  
  8. #include <conio.h>
  9. #include <io.h>
  10. #include <process.h>
  11. #include <values.h>
  12.  
  13. #include "sndclass.h"
  14.  
  15. #define DEFAULTRECORDLEN 10000000L        // 10 megabytes
  16.  
  17. // Forward function definitions
  18.  
  19. static void bar_display(char val);
  20. static void bar_display(int val);
  21.  
  22. // Function: setsizes
  23. // Given a buffer size ('bufsize') and remaining file length ('len'), this
  24. // determines lengths for the lower and upper half-buffers. It is used four
  25. // times in the file_dma function, so it is brought out here as an inline
  26. // function.
  27.  
  28. inline void SoundDevice::setsizes(unsigned &bufsize, long &len,
  29.                                     unsigned &lo_sz, unsigned &hi_sz) {
  30.     len -= (lo_sz = (bufsize < len) ? bufsize : (unsigned) len);
  31.     len -= (hi_sz = (bufsize < len) ? bufsize : (unsigned) len);
  32. }
  33.  
  34. // Function: file_dma
  35. // Handles the running of buffered DMA from a sound device to a disk file,
  36. // or in the opposite direction. 'handle' is the handle of a file opened
  37. // with _open(), 'lobuf' is a pointer to the bottom of the single DMA buffer,
  38. // 'bufsize' is the size of it (up to a maximum of 64K), 'len' is the desired
  39. // length of file to play (or zero for the full length) and 'dir' sets the
  40. // direction (recording or playback).
  41.  
  42. void SoundDevice::file_dma(int handle, byte far *lobuf, unsigned bufsize,
  43.                                                         long len, byte dir) {
  44.  
  45.     reset();
  46.     byte far *hibuf = lobuf + bufsize;  // Calculate pos of high half-buffer
  47.     unsigned lo_sz, hi_sz, cur_sz;
  48.     dt_min=65535U;                 // Initialise disk time statistics
  49.     dt_max=0;
  50.     if (dir == RECORD) {
  51.         if (len == 0) len = DEFAULTRECORDLEN;
  52.         setsizes(bufsize,len,lo_sz,hi_sz);
  53.         buf_dma_start(lobuf,lo_sz+hi_sz,RECORD);
  54.         // Wait for the transfer to start to avoid confusing buf_dma_lo().
  55.         while (dma_addr() == 0);
  56.         while (1) {
  57.             if (lo_sz == 0) break;
  58.             if (buf_dma_lo(lo_sz)) { // if terminated by keypress
  59.                 lo_sz = dma_addr();
  60.                 Dprint(("Saving up to position %u.\r\n",lo_sz));
  61.                 hi_sz = 0;
  62.             }
  63.             if (disk_io(handle,lobuf,lo_sz,RECORD)) return;
  64.             if (hi_sz == 0) break;
  65.             cur_sz = hi_sz;
  66.             setsizes(bufsize,len,lo_sz,hi_sz);
  67.             if (buf_dma_hi(cur_sz,lo_sz+hi_sz)) {
  68.                 cur_sz = dma_addr() - bufsize;
  69.                 Dprint(("Saving hibuf, length %u.\r\n",cur_sz));
  70.                 lo_sz = 0;
  71.             }
  72.             if (disk_io(handle,hibuf,cur_sz,RECORD)) return;
  73.         }
  74.     } else {                                         // Play function
  75.         if (len == 0) len = filelength(handle);
  76.         setsizes(bufsize,len,lo_sz,hi_sz);
  77.         if (lo_sz == 0) {
  78.             cprintf("Error: zero length.\r\n");
  79.             exit(-1);
  80.         }
  81.         if (_read(handle,lobuf,lo_sz) != lo_sz) {    // Fill first buffer
  82.             cprintf("File read error.\r\n");
  83.             exit(-1);
  84.         }
  85.         buf_dma_start(lobuf,lo_sz+hi_sz,PLAY);
  86.         while (dma_addr() == 0);               // Wait for it to start
  87.         while (1) {                            // Main buffer loop - forever
  88.             if (hi_sz == 0) {
  89.                 buf_dma_lo(lo_sz);
  90.                 break;
  91.             } else {
  92.                 if (disk_io(handle,hibuf,hi_sz,PLAY)) return;
  93.                 if (buf_dma_lo(lo_sz)) break;
  94.             }
  95.             if (len == 0) {
  96.                 buf_dma_hi(hi_sz, 0);
  97.                 break;
  98.             } else {
  99.                 setsizes(bufsize,len,lo_sz,hi_sz);
  100.                 if (disk_io(handle,lobuf,lo_sz,PLAY)) return;
  101.                 if (buf_dma_hi(bufsize, lo_sz+hi_sz)) break;
  102.             }
  103.         }
  104.     }
  105.     // At the end print out min and max times per disk access,
  106.     // in terms of both bytes and milliseconds.
  107.     unsigned bytes_per_ms =
  108.         (unsigned) (((long) get_rate() * get_width() + 500) / 1000);
  109.     cprintf("Disk stats: min %u (%ums), max %u (%ums).\r\n",
  110.     dt_min,
  111.     dt_min / bytes_per_ms,
  112.     dt_max,
  113.     dt_max / bytes_per_ms);
  114. }
  115.  
  116. // Function: disk_io
  117. // Takes care of the time-consuming disk reads/writes of file 'handle'
  118. // from/into buffer 'buf', of 'len' bytes in direction 'dir'.
  119. // Automatically measures the time taken in terms of the number of bytes
  120. // advanced by the DMA and updates the min/max times.
  121.  
  122. int SoundDevice::disk_io(int handle, byte far *buf, unsigned len, byte dir) {
  123.     unsigned old_addr = dma_addr();
  124.     if (dir == RECORD) {
  125.         if (_write(handle,buf,len) != len) {
  126.             cprintf("Write error: disk full?\r\n");
  127.             return 1;
  128.         }
  129.     } else {
  130.         if (_read(handle,buf,len) != len) {
  131.             cprintf("File read error.\r\n");
  132.             return 1;
  133.         }
  134.     }
  135.     unsigned new_addr = dma_addr();
  136.     unsigned disktime = new_addr - old_addr;
  137.     if (new_addr < old_addr) {
  138.         Dprint(("Long disk wait. "));   // Overflow - can't measure the time
  139.     } else {
  140.         if (disktime && disktime<dt_min) dt_min = disktime;
  141.         if (disktime>dt_max) dt_max = disktime;
  142.         Dprint(("DT = %X. ",disktime));
  143.     }
  144.     return 0;
  145. }
  146.  
  147. // Function: max
  148. // Defined both for integers and bytes, for use in monitor_input
  149.  
  150. inline int max(int v1, int v2) {
  151.     return (v1 > v2 ? v1 : v2);
  152. }
  153.  
  154. inline byte max(byte v1, byte v2) {
  155.     return (v1 > v2 ? v1 : v2);
  156. }
  157.  
  158. // Function: monitor_input
  159. // Displays input levels by continously reading in DMA for 'blocklen' bytes
  160. // and showing the maximum value within the block as a bar graph from left
  161. // to right. 80 columns represents full scale. The value chosen for
  162. // 'blocklen' affects the responsiveness and accuracy of the bar graph.
  163. // I have included code for both the SB (unsigned mono bytes) data format
  164. // and the CD (signed stereo words) format to demonstrate how both types can
  165. // be used.
  166.  
  167. void SoundDevice::monitor_input(byte far *dmabuf, unsigned blocklen) {
  168.     if (blocklen > 65000) {
  169.         cprintf("Use a smaller block length.\r\n");
  170.         return;
  171.     }
  172.     blocklen &= ~3;             // Round down to a double-word boundary
  173.     byte maxbyte;
  174.     int maxleft, maxright;
  175.     byte far *bdata;            // Different pointer types for SB (byte)
  176.     int far *idata;             // and CD (signed int)
  177.     byte far *data_end = dmabuf + blocklen;
  178.  
  179.     clrscr();      // Start by clearing the screen and disabling the cursor
  180.     _setcursortype(_NOCURSOR);
  181.     while (1) {
  182.         buf_dma_start(dmabuf,65500U,RECORD);
  183.         while ((dma_addr() < blocklen) && !kbhit());// Wait for buffer to fill
  184.         halt();                    // Prevent further DMA writes
  185.         reset();
  186.         if (kbhit()) break;
  187.         maxbyte = 0;               // Initialise max variables
  188.         maxleft = maxright = -MAXINT;
  189.         switch(identify()) { // Execute different loops depending on data type
  190.             case SB_ID:
  191.                 for (bdata = dmabuf; bdata < data_end; bdata++) {
  192.                     maxbyte = max(maxbyte, *bdata);
  193.                 }
  194.                 break;
  195.             case CD_ID:
  196.                 for (idata = (int *) dmabuf; idata < (int *) data_end; idata++) {
  197.                     maxleft = max(maxleft, *idata);
  198.                     idata++;
  199.                     maxright = max(maxright, *idata);
  200.                 }
  201.                 break;
  202.         }
  203.         gotoxy(1,1);               // Move invisible cursor to top left
  204.         switch (identify()) {
  205.             case SB_ID:            // Subtract 0x80 before displaying
  206.                 bar_display((char) (maxbyte - 128));
  207.                 break;
  208.             case CD_ID:
  209.                 bar_display(maxleft);
  210.                 bar_display(maxright);
  211.                 break;
  212.         }
  213.     }
  214.     getch();           // Remove character from keyboard buffer
  215.     _setcursortype(_NORMALCURSOR);   // Restore cursor
  216.     return;
  217. }
  218.  
  219. // Function: bar_display (signed byte)
  220. // Converts byte (0 to 7F) to int and calls the real bar_display function
  221.  
  222. static void bar_display(char val) {
  223.     int ival = val * (MAXINT / 127);
  224.     bar_display(ival);
  225. }
  226.  
  227. // Function: bar_display (int)
  228. // Prints a row of asterisks corresponding to the size of 'val'. Always
  229. // completes the line with spaces to eliminate any previous characters.
  230.  
  231. static void bar_display(int val) {
  232.     if (val < 0) val = 0;
  233.     int bar_len = val / (MAXINT / 80);
  234.     int i;
  235.     for (i = 0; i < 80; i++) {
  236.         putch(i <= bar_len ? '*' : ' ');
  237.     }
  238.     return;
  239. }